# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _
import gtk
import gobject
import os
import etude.gui as eg
import etude.client as ec

def create_add_to_playlist_menu(callback, client, enable_all=True, enable_selected=True):
    """
    Create popup menu for adding to playlist

    callback should be the form of:
        def callback(widget, playlist, selected)
    playlist is None if the actual is to be used
    selected if only the selected songs are to be added
    """
    menu = gtk.Menu()
    submenus = []
    if enable_selected:
        sel_item = gtk.MenuItem(label = _("Add selected")+"...")
        menu.append(sel_item)
        submenus.append((sel_item, True))
    if enable_all:
        all_item = gtk.MenuItem(label = _("Add all")+"...")
        menu.append(all_item)
        submenus.append((all_item, False))

    playlists = client.get_collections("Playlists")
    for submenu,param in submenus:
        pmenu = gtk.Menu()
        item = gtk.MenuItem(label= _("To current playlist"))
        item.connect('activate', callback, None, param)
        pmenu.append(item)
        
        item = gtk.MenuItem(label= _("To playlist")+"...")
        pmenu.append(item)
        
        pl_menu = gtk.Menu()
        for playlist in playlists:
            it = gtk.MenuItem(label= playlist)
            it.connect('activate', callback, playlist, param)
            pl_menu.append(it)
        it = gtk.MenuItem(label=_("New playlists")+"...")
        it.connect('activate', on_new_playlist, callback, client, param)
        pl_menu.append(it)
        item.set_submenu(pl_menu)

        submenu.set_submenu(pmenu)
    return menu

def on_new_playlist(widget, callback, client, *cb_args):
    """
    Create a new playlist
    """
    dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            gtk.MESSAGE_QUESTION,
            buttons=gtk.BUTTONS_OK_CANCEL
            )
    dialog.set_markup(_("Please enter the name of the new playlist:"))
    #inputfield
    entry = gtk.Entry()
    #allow using enter
    entry.connect('activate', lambda widget: dialog.response(gtk.RESPONSE_OK))
    
    #add entry:
    dialog.vbox.pack_end(entry, True, True)
    dialog.show_all()

    resp = dialog.run()
    if resp == gtk.RESPONSE_OK:
        e = entry.get_text()
        if e:
            client.playlist.create(e)
            dialog.destroy()
            if callback:
                callback(*([widget, e]+list(cb_args)))
    dialog.destroy()
    return False

def url_chooser_dialog(toplevel, entry_default=''):
        """
        Show a dialog for adding an url to a playlist/medialist
        """
        dialog = gtk.MessageDialog(toplevel, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                gtk.MESSAGE_QUESTION,
                buttons=gtk.BUTTONS_OK_CANCEL
                )
        dialog.set_markup(_("Please enter the url:"))
        #inputfield
        entry = gtk.Entry()
        entry.set_text(entry_default)
        #allow using enter
        entry.connect('activate', lambda widget: dialog.response(gtk.RESPONSE_OK))
        
        #add entry:
        dialog.vbox.pack_end(entry, True, True)
        dialog.show_all()

        resp = dialog.run()
        e = ''
        if resp == gtk.RESPONSE_OK:
            e = entry.get_text()
        dialog.destroy()
        return e

def filechooser(toplevel, control):
    music_dir = control.profile['music_dir']

    if control.profile.is_remote():
        return remote_filechooser(toplevel, control, music_dir)
    else:
        paths = local_filechooser(toplevel, music_dir)
        return [(os.path.isdir(path), "file://"+path) for path in paths]

def audio_filter_func(filter_info, data=None):
    #filter info tuple - (full_path, uri, display name, mime)
    return filter_info[3].startswith("audio/")

def local_filechooser(toplevel, music_dir):
    """
    Show the local filechooser with audio filters
    """
    #for the response add hack thx to lxmusic developer
    RESPONSE_ADD = 1
    dialog = gtk.FileChooserDialog( title=None, 
            parent=toplevel,
            action=gtk.FILE_CHOOSER_ACTION_OPEN,
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                gtk.STOCK_ADD, RESPONSE_ADD))
    dialog.set_select_multiple(True)
    filter = gtk.FileFilter()
    filter.set_name(_("Audio Files"))
    filter.add_custom(gtk.FILE_FILTER_MIME_TYPE, audio_filter_func, None)
    dialog.add_filter(filter)

    filter = gtk.FileFilter()
    filter.set_name(_("All Files"))
    filter.add_pattern( "*")
    dialog.add_filter(filter)
    dialog.set_current_folder(music_dir)
    
    t = dialog.run()
    paths = []
    if t == RESPONSE_ADD:
        paths = dialog.get_filenames()
    dialog.destroy()
    return paths

def remote_filechooser(toplevel, control, music_dir):
    """
    Show the filechooser through xmms2
    """
    RESPONSE_ADD = 1
    dialog = eg.RemoteFileDialog(toplevel, control, type='tree')
    if not music_dir.startswith('/'):
        music_dir = '/'+music_dir
    dialog.set_root('file://'+ music_dir)
    dialog.set_select_multiple()
    resp = dialog.run()
    paths = []
    if resp == RESPONSE_ADD:
        paths = dialog.get_selected()
    dialog.destroy()
    return paths

LIST_STRUCT_TOOLTIP=_("""
to group properties use {} - the contents are only shown if all the
properties inside are set

| is a column separator
<artist> - artist
<album> - album
<smart> - title or channel or filename in this order
<title> - title
<channel> - radio channel
<tracknr> - tracknumber
<url> - path - if file
<bitrate>- bitrate
<filename>- filename - if file
<duration> - song length
<date> - date
<genre> - genre
<comment> - comment""")

class CollectionSaverDialog(gtk.Dialog):

    """
    Dialog for saving collections
    """

    def __init__(self, parent, coll):
        gtk.Dialog.__init__(self, title = _("Save collection"),
                parent = parent.get_toplevel(),
                flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE,
                    gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        table = gtk.Table(rows = 6, columns = 2)
        table.set_row_spacings(5)
        table.set_col_spacings(5)
        self.client = parent.client

        self.collection = coll

        self.vbox.pack_start(table, True, True)

        table.attach(gtk.Label(_("Name")+':'), 0, 1, 0, 1,
                xoptions = 0, yoptions = 0)
        table.attach(gtk.Label(_("Namespace")+':'), 0, 1, 1, 2,
                xoptions = 0, yoptions = 0)
        table.attach(gtk.Label(_("Type")+':'), 0, 1, 2, 3,
                xoptions = 0, yoptions = 0)
        table.attach(gtk.Label(_("History")+':'), 0, 1, 3, 4,
                xoptions = 0, yoptions = 0)
        table.attach(gtk.Label(_("Upcoming")+':'), 0, 1, 4, 5,
                xoptions = 0, yoptions = 0)
        table.attach(gtk.Label(_("Jumplist")+':'), 0, 1, 5, 6,
                xoptions = 0, yoptions = 0)

        self.name_entry = gtk.Entry()
        table.attach(self.name_entry, 1, 2, 0, 1,
                xoptions = gtk.FILL|gtk.EXPAND, yoptions = 0)

        self.ns_combo = gtk.ComboBox()
        ns_combo_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        ns_combo_model.append( (_("Collections"), "Collections") )
        ns_combo_model.append( (_("Playlists"),"Playlists") )
        self.ns_combo.set_model(ns_combo_model)
        
        cell = gtk.CellRendererText()
        self.ns_combo.pack_start(cell, True)
        self.ns_combo.add_attribute(cell, 'text', 0)
        
        self.ns_combo.set_active(0)
        table.attach(self.ns_combo, 1, 2, 1, 2,
                xoptions = gtk.FILL|gtk.EXPAND, yoptions = 0)

        self.type_combo = gtk.ComboBox()
        type_combo_model = gtk.ListStore(gobject.TYPE_STRING,
                gobject.TYPE_PYOBJECT)
        cl = ec.Collection(None)
        type_combo_model.append( (_("IDList"), cl.IDList) )
        type_combo_model.append( (_("Queue"), cl.Queue) )
        type_combo_model.append( (_("Party Shuffle"), cl.PShuffle) )
        self.type_combo.set_model(type_combo_model)
        self.type_combo.set_active(0)
        self.type_combo.set_sensitive(False)

        cell = gtk.CellRendererText()
        self.type_combo.pack_start(cell, True)
        self.type_combo.add_attribute(cell, 'text', 0)

        table.attach(self.type_combo, 1, 2 , 2, 3,
                xoptions = gtk.FILL|gtk.EXPAND, yoptions = 0)
        self.type_combo.set_tooltip_markup(_("""
        * ID list: a static list of media ids.
        * Queue: a static list of media ids. When used as a playlist, 
            played songs are popped out of it. The history property specifies 
            how many played songs are kept before they are removed.
        * Party shuffle: a static list of media ids, populated by a random 
            selection of songs from the input collection until the list size 
            reaches the upcoming property. Played songs are popped similarly 
            to the queue, using the history property."""))

        self.history = gtk.SpinButton()
        self.history.set_range(0, 10000)
        self.history.set_increments(1, 5)
        if 'history' in coll.attributes:
            self.history.set_value( int(coll.attributes['history']) )
        else:
            self.history.set_value(0)
        self.history.set_sensitive(False)
        table.attach(self.history, 1, 2, 3, 4, xoptions = 0, yoptions = 0)
        self.history.set_tooltip_text(_("The history property specifies how many played songs \
are kept before they are removed."))

        self.upcoming = gtk.SpinButton()
        self.upcoming.set_range(1, 10000)
        self.upcoming.set_increments(1, 5)
        if 'upcoming' in coll.attributes:
            self.upcoming.set_value(int(coll.attributes['upcoming']))
        else:
            self.upcoming.set_value(30)
        self.upcoming.set_sensitive(False)
        table.attach(self.upcoming, 1, 2, 4, 5, xoptions = 0, yoptions = 0)
        self.upcoming.set_tooltip_text(_("Party Shuffle is populated by a random selection of \
songs from the input collection until the list size reaches \
the upcoming property."))

        
        collections = self.client.get_collections('Playlists')
        self.jumplist = gtk.combo_box_entry_new_text()
        if 'jumplist' in coll.attributes:
            active = coll.attributes['jumplist']
        else:
            active = ''
        for col_name in collections:
            self.jumplist.append_text(col_name)
            if active == col_name:
                self.jumplist.set_active(collections.index(col_name))
        if (self.jumplist.get_active() == -1) and (active != ''):
            self.jumplist.prepend(active)
            self.jumplist.set_active(0)
        self.jumplist.set_sensitive(False)

        table.attach(self.jumplist, 1, 2, 5, 6, xoptions = 0, yoptions = 0)
        
        self.ns_combo.connect('changed', self.ns_combo_changed)
        self.type_combo.connect('changed', self.type_combo_changed)
        self.show_all()
 
    def type_combo_changed(self, combobox, data = None):
        """
        The type of the collection changed - enable disable
        properties accerdingly
        """
        model = combobox.get_model()
        act_iter = combobox.get_active_iter()
        val = model.get_value(act_iter, 1)
        cl = ec.Collection(None)
        if (combobox.get_property('sensitive') == False) or (val == cl.IDList):
            self.history.set_sensitive(False)
            self.upcoming.set_sensitive(False)
        elif val == cl.Queue:
            self.history.set_sensitive(True)
            self.upcoming.set_sensitive(False)
        elif val == cl.PShuffle:
            self.history.set_sensitive(True)
            self.upcoming.set_sensitive(True)
        return False
    
    def ns_combo_changed(self, combobox, data = None):
        """the namespace changed"""
        model = combobox.get_model()
        act_iter = combobox.get_active_iter()
        is_playlist = model.get_value(act_iter, 1) == "Playlists"
        self.type_combo.set_sensitive(is_playlist)
        self.jumplist.set_sensitive(is_playlist)
        self.type_combo_changed(self.type_combo)
        return False

    def get_name(self):
        """Get the new name"""
        return self.name_entry.get_text()
    
    def get_ns(self):
        """get the namespace"""
        model = self.ns_combo.get_model()
        act_iter = self.ns_combo.get_active_iter()
        return model.get_value(act_iter, 1)

    def get_coll(self, get_ids_callback=None, 
            ignore_idlist_namespace=False):
        """Get the result collection of the editing"""
        cl = ec.Collection(None)
        coll_type = self.get_type()
        jumplist = self.get_jumplist()
        namespace = self.get_ns()
        ret_coll = None
        if namespace == "Playlists" or ignore_idlist_namespace:
            if coll_type == cl.IDList:
                ret_coll = cl.IDList()
            elif coll_type == cl.Queue:
                ret_coll = cl.Queue()
                ret_coll.attributes['history'] = str(self.get_history())
            elif coll_type == cl.PShuffle:
                ret_coll = cl.PShuffle(self.collection)
                ret_coll.attributes['upcoming'] = str(self.get_upcoming())
                ret_coll.attributes['history'] = str(self.get_history())
            if ret_coll:
                if coll_type != cl.PShuffle:
                    ids = []
                    if cl.check_medialist(self.collection):
                        ids = iter(self.collection.ids)
                    elif hasattr(get_ids_callback, '__call__'):
                        ids = iter(get_ids_callback())

                    [ret_coll.ids.append(song_id) for song_id in ids]
                if jumplist:
                    ret_coll.attributes['jumplist'] = jumplist
        else:
            ret_coll = self.collection
        return ret_coll

    def get_type(self):
        """get the type of the collection"""
        model = self.type_combo.get_model()
        act_iter = self.type_combo.get_active_iter()
        return model.get_value(act_iter, 1)

    def get_history(self):
        """get the history property"""
        return self.history.get_value_as_int()

    def get_jumplist(self):
        """get the jumplist settings"""
        return self.jumplist.get_active_text()

    def get_upcoming(self):
        """get the number of upcoming songs"""
        return self.upcoming.get_value_as_int()

    def check_name(self):
        name = self.get_name()
        if (len(name) == 0) or (name.startswith('_')):
            self.show_name_error()
            return False
        return name

    def show_name_error(self):
        dd = gtk.MessageDialog(
                self, 0, gtk.MESSAGE_QUESTION, gtk.BUTTONS_CLOSE,
                _("The name of the collection must not be empty and must not start with _")
                )
        dd.run()
        dd.destroy()

